"""
配置管理模块
负责管理所有系统配置，包括账户信息、策略参数、风险控制参数等
"""

import json
import os
from pathlib import Path
from typing import Dict, Any, Optional
from cryptography.fernet import Fernet
import base64
import logging


class ConfigManager:
    """配置管理器类"""
    
    def __init__(self, config_dir: str = ".settings"):
        """
        初始化配置管理器
        
        Args:
            config_dir: 配置文件目录路径
        """
        self.config_dir = Path(config_dir)
        self.config_dir.mkdir(exist_ok=True)
        
        # 配置文件路径
        self.config_files = {
            'accounts': self.config_dir / 'accounts.json',
            'strategies': self.config_dir / 'strategies.json',
            'risk_management': self.config_dir / 'risk_management.json',
            'system': self.config_dir / 'system.json'
        }
        
        # 加密密钥文件
        self.key_file = self.config_dir / '.encryption_key'
        self._encryption_key = None
        
        # 初始化日志
        self.logger = logging.getLogger(__name__)
        
        # 创建默认配置文件
        self._create_default_configs()
    
    def _get_encryption_key(self) -> bytes:
        """获取或创建加密密钥"""
        if self._encryption_key is None:
            if self.key_file.exists():
                with open(self.key_file, 'rb') as f:
                    self._encryption_key = f.read()
            else:
                # 生成新的加密密钥
                self._encryption_key = Fernet.generate_key()
                with open(self.key_file, 'wb') as f:
                    f.write(self._encryption_key)
                # 设置文件权限为只读
                os.chmod(self.key_file, 0o600)
        
        return self._encryption_key
    
    def encrypt_sensitive_data(self, data: str) -> str:
        """
        加密敏感数据
        
        Args:
            data: 要加密的字符串
            
        Returns:
            加密后的字符串
        """
        try:
            key = self._get_encryption_key()
            fernet = Fernet(key)
            encrypted_data = fernet.encrypt(data.encode())
            return base64.b64encode(encrypted_data).decode()
        except Exception as e:
            self.logger.error(f"数据加密失败: {e}")
            raise
    
    def decrypt_sensitive_data(self, encrypted_data: str) -> str:
        """
        解密敏感数据
        
        Args:
            encrypted_data: 加密的字符串
            
        Returns:
            解密后的字符串
        """
        try:
            key = self._get_encryption_key()
            fernet = Fernet(key)
            decoded_data = base64.b64decode(encrypted_data.encode())
            decrypted_data = fernet.decrypt(decoded_data)
            return decrypted_data.decode()
        except Exception as e:
            self.logger.error(f"数据解密失败: {e}")
            raise
    
    def load_config(self, config_type: str) -> Dict[str, Any]:
        """
        加载配置文件
        
        Args:
            config_type: 配置类型 ('accounts', 'strategies', 'risk_management', 'system')
            
        Returns:
            配置字典
        """
        if config_type not in self.config_files:
            raise ValueError(f"不支持的配置类型: {config_type}")
        
        config_file = self.config_files[config_type]
        
        try:
            if config_file.exists():
                with open(config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                self.logger.info(f"成功加载配置文件: {config_file}")
                return config
            else:
                self.logger.warning(f"配置文件不存在: {config_file}")
                return {}
        except json.JSONDecodeError as e:
            self.logger.error(f"配置文件格式错误 {config_file}: {e}")
            raise ValueError(f"配置文件格式错误: {e}")
        except Exception as e:
            self.logger.error(f"加载配置文件失败 {config_file}: {e}")
            raise
    
    def save_config(self, config_type: str, config: Dict[str, Any]) -> bool:
        """
        保存配置文件
        
        Args:
            config_type: 配置类型
            config: 配置字典
            
        Returns:
            保存是否成功
        """
        if config_type not in self.config_files:
            raise ValueError(f"不支持的配置类型: {config_type}")
        
        config_file = self.config_files[config_type]
        
        try:
            with open(config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
            self.logger.info(f"成功保存配置文件: {config_file}")
            return True
        except Exception as e:
            self.logger.error(f"保存配置文件失败 {config_file}: {e}")
            return False
    
    def get_account_config(self, account_name: str) -> Dict[str, Any]:
        """
        获取指定账户配置
        
        Args:
            account_name: 账户名称
            
        Returns:
            账户配置字典
        """
        accounts_config = self.load_config('accounts')
        
        if account_name not in accounts_config:
            raise ValueError(f"账户配置不存在: {account_name}")
        
        account_config = accounts_config[account_name].copy()
        
        # 解密敏感信息
        if 'password' in account_config and account_config['password'].startswith('encrypted:'):
            encrypted_password = account_config['password'][10:]  # 移除 'encrypted:' 前缀
            account_config['password'] = self.decrypt_sensitive_data(encrypted_password)
        
        return account_config
    
    def get_auth_object(self, account_name: str):
        """
        获取指定账户的认证对象
        
        Args:
            account_name: 账户名称
            
        Returns:
            认证对象 (TqAuth)
        """
        from tqsdk import TqAuth
        
        account_config = self.get_account_config(account_name)
        broker = account_config.get('broker', '').lower()
        
        if broker == 'tqsdk':
            # 天勤量化账户
            return TqAuth(account_config['user_id'], account_config['password'])
        else:
            # 所有账户都使用天勤认证
            return TqAuth(account_config['user_id'], account_config['password'])
    
    def get_account_object(self, account_name: str):
        """
        获取指定账户的TqAccount对象
        
        Args:
            account_name: 账户名称
            
        Returns:
            TqAccount对象
        """
        from tqsdk import TqAccount
        
        account_config = self.get_account_config(account_name)
        
        return TqAccount(
            account_config['broker'],
            account_config['user_id'], 
            account_config['password']
        )
    
    def get_strategy_config(self, strategy_name: str) -> Dict[str, Any]:
        """
        获取指定策略配置
        
        Args:
            strategy_name: 策略名称
            
        Returns:
            策略配置字典
        """
        strategies_config = self.load_config('strategies')
        
        if strategy_name not in strategies_config:
            raise ValueError(f"策略配置不存在: {strategy_name}")
        
        return strategies_config[strategy_name]
    
    def get_risk_config(self) -> Dict[str, Any]:
        """
        获取风险管理配置
        
        Returns:
            风险管理配置字典
        """
        return self.load_config('risk_management')
    
    def get_system_config(self) -> Dict[str, Any]:
        """
        获取系统配置
        
        Returns:
            系统配置字典
        """
        return self.load_config('system')
    
    def _create_default_configs(self):
        """创建默认配置文件模板"""
        # 创建默认账户配置模板（空文件，用户需要自行配置）
        if not self.config_files['accounts'].exists():
            default_accounts = {
                "_template": {
                    "broker": "请填写券商代码",
                    "user_id": "请填写用户ID", 
                    "password": "请填写密码",
                    "app_id": "请填写应用ID",
                    "auth_code": "请填写授权码",
                    "td_url": "请填写交易服务器地址",
                    "md_url": "请填写行情服务器地址",
                    "enabled": False,
                    "description": "配置模板，请复制此模板并填写真实信息，然后删除此模板"
                }
            }
            self.save_config('accounts', default_accounts)
        
        # 创建默认策略配置
        if not self.config_files['strategies'].exists():
            default_strategies = {
                "macd_kdj_strategy": {
                    "type": "rule_based",
                    "symbol": "SHFE.rb2501",
                    "enabled": False,
                    "auto_start": False,
                    "parameters": {
                        "macd_fast": 12,
                        "macd_slow": 26,
                        "macd_signal": 9,
                        "kdj_period": 9,
                        "kdj_k": 3,
                        "kdj_d": 3
                    },
                    "risk_params": {
                        "max_position": 10,
                        "stop_loss_pct": 0.02,
                        "take_profit_pct": 0.04
                    },
                    "description": "MACD+KDJ组合策略"
                }
            }
            self.save_config('strategies', default_strategies)
        
        # 创建默认风险管理配置
        if not self.config_files['risk_management'].exists():
            default_risk = {
                "global_limits": {
                    "max_daily_loss": 10000,
                    "max_drawdown": 0.1,
                    "max_position_per_symbol": 50,
                    "position_concentration_limit": 0.3,
                    "margin_ratio_limit": 0.8
                },
                "stop_loss": {
                    "enabled": True,
                    "default_pct": 0.02,
                    "trailing_stop": False
                },
                "take_profit": {
                    "enabled": True,
                    "default_pct": 0.04
                },
                "emergency_controls": {
                    "auto_close_on_loss": True,
                    "auto_close_threshold": 0.05,
                    "notification_enabled": True
                }
            }
            self.save_config('risk_management', default_risk)
        
        # 创建默认系统配置
        if not self.config_files['system'].exists():
            default_system = {
                "logging": {
                    "level": "INFO",
                    "file_path": "logs/system.log",
                    "max_file_size": "10MB",
                    "backup_count": 5
                },
                "data": {
                    "cache_enabled": True,
                    "cache_duration_hours": 24,
                    "auto_cleanup": True,
                    "data_source": "tqsdk"
                },
                "monitoring": {
                    "health_check_interval": 60,
                    "performance_log_interval": 300,
                    "notification_enabled": True
                },
                "api": {
                    "timeout": 30,
                    "retry_count": 3,
                    "retry_delay": 1
                }
            }
            self.save_config('system', default_system)
    
    def validate_config(self, config_type: str) -> tuple[bool, list]:
        """
        验证配置文件格式
        
        Args:
            config_type: 配置类型
            
        Returns:
            (是否有效, 错误列表)
        """
        errors = []
        
        try:
            config = self.load_config(config_type)
            
            if config_type == 'accounts':
                for account_name, account_config in config.items():
                    required_fields = ['broker', 'user_id', 'password']
                    for field in required_fields:
                        if field not in account_config:
                            errors.append(f"账户 {account_name} 缺少必需字段: {field}")
            
            elif config_type == 'strategies':
                for strategy_name, strategy_config in config.items():
                    required_fields = ['type', 'symbol', 'parameters']
                    for field in required_fields:
                        if field not in strategy_config:
                            errors.append(f"策略 {strategy_name} 缺少必需字段: {field}")
            
            elif config_type == 'risk_management':
                required_sections = ['global_limits', 'stop_loss', 'take_profit']
                for section in required_sections:
                    if section not in config:
                        errors.append(f"风险管理配置缺少必需部分: {section}")
            
            elif config_type == 'system':
                required_sections = ['logging', 'data', 'monitoring']
                for section in required_sections:
                    if section not in config:
                        errors.append(f"系统配置缺少必需部分: {section}")
            
        except Exception as e:
            errors.append(f"配置文件验证失败: {e}")
        
        return len(errors) == 0, errors